Wang Haihua
🚅 🚋😜 🚑 🚔
# -*- coding: utf-8 -*-
"""
粒子群算法求解TSP问题
随机在(0,101)二维平面生成20个点
距离最小化
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
def calDistance(CityCoordinates):
'''
计算城市间距离
输入:CityCoordinates-城市坐标;
输出:城市间距离矩阵-dis_matrix
'''
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
if (xi==xj) & (yi==yj):
dis_matrix.iloc[i,j] = round(math.pow(10,10))
else:
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
return dis_matrix
def calFitness(line,dis_matrix):
'''
计算路径距离,即评价函数
输入:line-路径,dis_matrix-城市间距离矩阵;
输出:路径距离-dis_sum
'''
dis_sum = 0
dis = 0
for i in range(len(line)-1):
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
dis = dis_matrix.loc[line[-1],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def draw_path(line,CityCoordinates):
'''
#画路径图
输入:line-路径,CityCoordinates-城市坐标;
输出:路径图
'''
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
def crossover(bird,pLine,gLine,w,c1,c2):
'''
采用顺序交叉方式;交叉的parent1为粒子本身,分别以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)
的概率接受粒子本身逆序、当前最优解、全局最优解作为parent2,只选择其中一个作为parent2;
输入:bird-粒子,pLine-当前最优解,gLine-全局最优解,w-惯性因子,c1-自我认知因子,c2-社会认知因子;
输出:交叉后的粒子-croBird;
'''
croBird = [None]*len(bird)#初始化
parent1 = bird#选择parent1
#选择parent2(轮盘赌操作)
randNum = random.uniform(0, sum([w,c1,c2]))
if randNum <= w:
parent2 = [bird[i] for i in range(len(bird)-1,-1,-1)] # bird的逆序
elif randNum <= w+c1:
parent2 = pLine
else:
parent2 = gLine
#parent1-> croBird
start_pos = random.randint(0,len(parent1)-1)
end_pos = random.randint(0,len(parent1)-1)
if start_pos>end_pos:
start_pos,end_pos = end_pos,start_pos
croBird[start_pos:end_pos+1] = parent1[start_pos:end_pos+1].copy()
# parent2 -> croBird
list1 = list(range(0,start_pos))
list2 = list(range(end_pos+1,len(parent2)))
list_index = list1+list2#croBird从后往前填充
#j = -1
for i in list_index:
for j in range(0,len(parent2)+1):
if parent2[j] not in croBird:
croBird[i] = parent2[j]
break
return croBird
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
iterMax = 200#迭代次数
iterI = 1#当前迭代次数
#PSO参数
birdNum = 100#粒子数量
w = 0.2#惯性因子
c1 = 0.4#自我认知因子
c2 = 0.4#社会认知因子
pBest,pLine =0,[]#当前最优值、当前最优解,(自我认知部分)
gBest,gLine = 0,[]#全局最优值、全局最优解,(社会认知部分)
#随机生成城市数据,城市序号为0,1,2,3...
# CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]
dis_matrix = calDistance(CityCoordinates)#计算城市间距离,生成矩阵
birdPop = [random.sample(range(len(CityCoordinates)),len(CityCoordinates)) for i in range(birdNum)]#初始化种群,随机生成
fits = [calFitness(birdPop[i],dis_matrix) for i in range(birdNum)]#计算种群适应度
gBest = pBest = min(fits)#全局最优值、当前最优值
gLine = pLine = birdPop[fits.index(min(fits))]#全局最优解、当前最优解
while iterI <= iterMax:#迭代开始
for i in range(len(birdPop)):
birdPop[i] = crossover(birdPop[i],pLine,gLine,w,c1,c2)
fits[i] = calFitness(birdPop[i],dis_matrix)
pBest,pLine = min(fits),birdPop[fits.index(min(fits))]
if min(fits) <= gBest:
gBest,gLine = min(fits),birdPop[fits.index(min(fits))]
#print(iterI,gBest)#打印当前代数和最佳适应度值
iterI += 1#迭代计数加一
print(gLine)#路径顺序
print(gBest)
draw_path(gLine,CityCoordinates)#画路径图
[12, 17, 5, 16, 6, 2, 19, 15, 1, 7, 10, 4, 8, 14, 13, 18, 9, 3, 11, 0] 437.1
def calFitness(line,dis_matrix):
dis_sum = 0
dis = 0
for i in range(len(line)):
if i<len(line)-1:
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
else:
dis = dis_matrix.loc[line[i],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def tournament_select(pops,popsize,fits,tournament_size):
new_pops,new_fits = [],[]
while len(new_pops)<len(pops):
tournament_list = random.sample(range(0,popsize),tournament_size)
tournament_fit = [fits[i] for i in tournament_list]
#转化为df方便索引
tournament_df = pd.DataFrame([tournament_list,tournament_fit]).transpose().sort_values(by=1).reset_index(drop=True)
#选出获胜者
fit = tournament_df.iloc[0,1]
pop = pops[int(tournament_df.iloc[0,0])]
new_pops.append(pop)
new_fits.append(fit)
return new_pops,new_fits
def crossover(popsize,parent1_pops,parent2_pops,pc):
child_pops = []
for i in range(popsize):
#初始化
child = [None]*len(parent1_pops[i])
parent1 = parent1_pops[i]
parent2 = parent2_pops[i]
if random.random() >= pc:
child = parent1.copy()#随机生成一个(或者随机保留父代中的一个)
random.shuffle(child)
else:
#parent1
start_pos = random.randint(0,len(parent1)-1)
end_pos = random.randint(0,len(parent1)-1)
if start_pos>end_pos:
tem_pop = start_pos
start_pos = end_pos
end_pos = tem_pop
child[start_pos:end_pos+1] = parent1[start_pos:end_pos+1].copy()
# parent2 -> child
list1 = list(range(end_pos+1,len(parent2)))
list2 = list(range(0,start_pos))
list_index = list1+list2
#j = -1
for i in list_index:
for j in range(0,len(parent2)):
if parent2[j] not in child:
child[i] = parent2[j]
break
child_pops.append(child)
return child_pops
def mutate(pops,pm):
pops_mutate = []
for i in range(len(pops)):
pop = pops[i].copy()
#随机多次成对变异
t = random.randint(1,5)
count = 0
while count < t:
if random.random() < pm:
mut_pos1 = random.randint(0,len(pop)-1)
mut_pos2 = random.randint(0,len(pop)-1)
if mut_pos1 != mut_pos2:
tem = pop[mut_pos1]
pop[mut_pos1] = pop[mut_pos2]
pop[mut_pos2] = tem
pops_mutate.append(pop)
count +=1
return pops_mutate
#另一种实现方式
# def mutate(pops,pm):
# pops_mutate = []
# for i in range(len(pops)):
# pop = pops[i].copy()
# for j in range(len(pop)):
# if random.random() < pm:
# mut_pos = random.randint(0,len(pop)-1)
# if j != mut_pos:
# tem = pop[j]
# pop[j] = pop[mut_pos]
# pop[mut_pos] = tem
# pops_mutate.append(pop)
# return pops_mutate
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
#画路径图
def draw_path(line,CityCoordinates):
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
#GA参数
generation = 100 #迭代次数
popsize = 100 #种群大小
tournament_size = 5 #锦标赛小组大小
pc = 0.95 #交叉概率
pm = 0.1 #变异概率
#随机生成城市数据,城市序号为0,1,2,3...
CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
# CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]#随机生成的例子
#计算城市之间的距离
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
iteration = 0
#初始化,随机构造
pops = [random.sample([i for i in list(range(len(CityCoordinates)))],len(CityCoordinates)) for j in range(popsize)]
#计算适应度
fits = [None]*popsize
for i in range(popsize):
fits[i] = calFitness(pops[i],dis_matrix)
#保留当前最优
best_fit = min(fits)
best_pop = pops[fits.index(best_fit)]
print('初代最优值 %.1f' % (best_fit))
best_fit_list = []
best_fit_list.append(best_fit)
while iteration <= generation:
#锦标赛赛选择
pop1,fits1 = tournament_select(pops,popsize,fits,tournament_size)
pop2,fits2 = tournament_select(pops,popsize,fits,tournament_size)
#交叉
child_pops = crossover(popsize,pop1,pop2,pc)
#变异
child_pops = mutate(child_pops,pm)
#计算子代适应度
child_fits = [None]*popsize
for i in range(popsize):
child_fits[i] = calFitness(child_pops[i],dis_matrix)
#一对一生存者竞争
for i in range(popsize):
if fits[i] > child_fits[i]:
fits[i] = child_fits[i]
pops[i] = child_pops[i]
if best_fit>min(fits):
best_fit = min(fits)
best_pop = pops[fits.index(best_fit)]
best_fit_list.append(best_fit)
#print('第%d代最优值 %.1f' % (iteration, best_fit))
iteration += 1
#路径顺序
print(best_pop)
print(best_fit)
#路径图
draw_path(best_pop,CityCoordinates)
#迭代图
iters = list(range(len(best_fit_list)))
plt.plot(iters, best_fit_list, '-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('迭代次数')
#show
初代最优值 899.9 [18, 6, 19, 12, 2, 9, 0, 15, 17, 3, 8, 13, 16, 7, 4, 11, 5, 1, 10, 14] 510.2
# -*- coding: utf-8 -*-
"""
禁忌搜索算法求解TSP问题
随机在(0,101)二维平面生成20个点
距离最小化
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
#计算路径距离,即评价函数
def calFitness(line,dis_matrix):
dis_sum = 0
dis = 0
for i in range(len(line)):
if i<len(line)-1:
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
else:
dis = dis_matrix.loc[line[i],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def traversal_search(line,dis_matrix,tabu_list):
#邻域随机遍历搜索
traversal = 0#搜索次数
traversal_list = []#存储局部搜索生成的解,也充当局部禁忌表
traversal_value = []#存储局部解对应路径距离
while traversal <= traversalMax:
pos1,pos2 = random.randint(0,len(line)-1),random.randint(0,len(line)-1)#交换点
#复制当前路径,并交换生成新路径
new_line = line.copy()
new_line[pos1],new_line[pos2]=new_line[pos2],new_line[pos1]
new_value = calFitness(new_line,dis_matrix)#当前路径距离
#新生成路径不在全局禁忌表和局部禁忌表中,为有效搜索,否则继续搜索
if (new_line not in traversal_list) & (new_line not in tabu_list):
traversal_list.append(new_line)
traversal_value.append(new_value)
traversal += 1
return min(traversal_value),traversal_list[traversal_value.index(min(traversal_value))]
def greedy(CityCoordinates,dis_matrix):
'''贪婪策略构造初始解'''
#出来dis_matrix
dis_matrix = dis_matrix.astype('float64')
for i in range(len(CityCoordinates)):
dis_matrix.loc[i,i]=math.pow(10,10)
line = []#初始化
now_city = random.randint(0,len(CityCoordinates)-1)#随机生成出发城市
line.append(now_city)#添加当前城市到路径
dis_matrix.loc[:,now_city] = math.pow(10,10)#更新距离矩阵,已经过城市不再被取出
for i in range(len(CityCoordinates)-1):
next_city = dis_matrix.loc[now_city,:].idxmin()#距离最近的城市
line.append(next_city)#添加进路径
dis_matrix.loc[:,next_city] = math.pow(10,10)#更新距离矩阵
now_city = next_city#更新当前城市
return line
#画路径图
def draw_path(line,CityCoordinates):
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
#TS参数
tabu_limit = 50 #禁忌长度,该值应小于(CityNum*(CityNum-1)/2)
iterMax = 200#迭代次数
traversalMax = 100#每一代局部搜索次数
tabu_list = [] #禁忌表
tabu_time = [] #禁忌次数
best_value = math.pow(10,10)#较大的初始值,存储最优解
best_line = []#存储最优路径
#随机生成城市数据,城市序号为0,1,2,3...
#CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]
#计算城市之间的距离
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
# #初始化,随机构造
# line = list(range(len(CityCoordinates)));random.shuffle(line)
# value = calFitness(line,dis_matrix)#初始路径距离
# 贪婪构造
line = greedy(CityCoordinates,dis_matrix)
value = calFitness(line,dis_matrix)#初始路径距离
#存储当前最优
best_value,best_line = value,line
draw_path(best_line,CityCoordinates)
best_value_list = []
best_value_list.append(best_value)
#更新禁忌表
tabu_list.append(line)
tabu_time.append(tabu_limit)
itera = 0
while itera <= iterMax:
new_value,new_line = traversal_search(line,dis_matrix,tabu_list)
if new_value < best_value:#优于最优解
best_value,best_line = new_value,new_line#更新最优解
best_value_list.append(best_value)
line,value = new_line,new_value#更新当前解
#更新禁忌表
tabu_time = [x-1 for x in tabu_time]
if 0 in tabu_time:
tabu_list.remove(tabu_list[tabu_time.index(0)])
tabu_time.remove(0)
tabu_list.append(line)
tabu_time.append(tabu_limit)
itera +=1
#路径顺序
print(best_line)
#画路径图
draw_path(best_line,CityCoordinates)
print(best_value)
# show
[4, 0, 11, 3, 9, 18, 13, 14, 8, 17, 12, 5, 16, 6, 2, 19, 15, 1, 7, 10]
465.6
# -*- coding: utf-8 -*-
"""
模拟退火算法法求解TSP问题
随机在(0,101)二维平面生成20个点
距离最小化
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
#计算路径距离,即评价函数
def calFitness(line,dis_matrix):
dis_sum = 0
dis = 0
for i in range(len(line)):
if i<len(line)-1:
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
else:
dis = dis_matrix.loc[line[i],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def traversal_search(line,dis_matrix):
#随机交换生成100个个体,选择其中表现最好的返回
i = 0#生成个体计数
line_value,line_list = [],[]
while i<=100:
new_line = line.copy()#复制当前路径
exchange_max = random.randint(1,5)#随机生成交换次数,城市数量较多时增加随机数上限效果较好
exchange_time = 0#当前交换次数
while exchange_time <= exchange_max:
pos1,pos2 = random.randint(0,len(line)-1),random.randint(0,len(line)-1)#交换点
new_line[pos1],new_line[pos2]=new_line[pos2],new_line[pos1]#交换生成新路径
exchange_time += 1#更新交换次数
new_value = calFitness(new_line,dis_matrix)#当前路径距离
line_list.append(new_line)
line_value.append(new_value)
i+=1
return min(line_value),line_list[line_value.index(min(line_value))]#返回表现最好的个体
def greedy(CityCoordinates,dis_matrix):
'''贪婪策略构造初始解'''
#转换格式—dis_matrix
dis_matrix = dis_matrix.astype('float64')
for i in range(len(CityCoordinates)):
dis_matrix.loc[i,i]=math.pow(10,10)
line = []#初始化
now_city = random.randint(0,len(CityCoordinates)-1)#随机生成出发城市
line.append(now_city)#添加当前城市到路径
dis_matrix.loc[:,now_city] = math.pow(10,10)#更新距离矩阵,已经过城市不再被取出
for i in range(len(CityCoordinates)-1):
next_city = dis_matrix.loc[now_city,:].idxmin()#距离最近的城市
line.append(next_city)#添加进路径
dis_matrix.loc[:,next_city] = math.pow(10,10)#更新距离矩阵
now_city = next_city#更新当前城市
return line
#画路径图
def draw_path(line,CityCoordinates):
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
#SA参数
Tend = 0.1#终止温度
T = 100#初温
beta = 0.99#退火步长
best_value = math.pow(10,10)#较大的初始值,存储最优解
best_line = []#存储最优路径
#随机生成城市数据,城市序号为0,1,2,3...
# CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]
#计算城市之间的距离
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
# 随机构造初始解
# line = list(range(len(CityCoordinates)));random.shuffle(line)
# value = calFitness(line,dis_matrix)#初始路径距离
# 贪婪构造初始解
line = greedy(CityCoordinates,dis_matrix)
value = calFitness(line,dis_matrix)#初始路径距离
#存储当前最优
best_value,best_line = value,line
draw_path(best_line,CityCoordinates)#初始路径
while T >= Tend:
new_value,new_line = traversal_search(line,dis_matrix)
# print(random.random(),math.exp(-(new_value-value)/T))
if new_value <= best_value:#优于最优解
best_value,best_line = new_value,new_line#更新最优解
line,value = new_line,new_value#更新当前解
elif random.random() < math.exp(-(new_value-value)/T):
line,value = new_line,new_value#更新当前解
#print('当前最优值 %.1f' % (best_value))
T *= beta
#路径顺序
print('当前最优值 %.1f' % (best_value))
print(best_line)
#画图
draw_path(best_line,CityCoordinates)
#show
当前最优值 438.6 [16, 15, 6, 2, 19, 1, 7, 10, 4, 8, 14, 13, 18, 9, 3, 11, 0, 12, 17, 5]
# -*- coding: utf-8 -*-
"""
模拟退火算法法求解TSP问题
随机在(0,101)二维平面生成20个点
距离最小化
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
#计算路径距离,即评价函数
def calFitness(line,dis_matrix):
dis_sum = 0
dis = 0
for i in range(len(line)):
if i<len(line)-1:
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
else:
dis = dis_matrix.loc[line[i],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def greedy(CityCoordinates,dis_matrix,p):
'''贪婪策略构造初始解,基于概率扰动'''
#更改dis_matrix格式
dis_matrix = dis_matrix.astype('float64')
for i in range(len(CityCoordinates)):
dis_matrix.loc[i,i]=math.pow(10,10)
line = []#初始化,存放路径
now_city = random.randint(0,len(CityCoordinates)-1)#随机生成出发城市
line.append(now_city)#添加当前城市到路径
dis_matrix.loc[:,now_city] = math.pow(10,10)#更新距离矩阵,已途径城市不再被取出
i = 1#当前已排好城市个数
j = 0#记录当前城市已遍历临近城市次数
while len(CityCoordinates)-i>0:
next_city = dis_matrix.loc[now_city,:].idxmin()#距离该城市最近的城市
j += 1
if j == len(CityCoordinates)-i:#是否为当前可遍历最后一个城市,是则直接添加——防止所有城市都不被取出的情况
line.append(next_city)#添加进路径
dis_matrix.loc[:,next_city] = math.pow(10,10)#更新距离矩阵
now_city = next_city#更新当前城市
i += 1
j = 0#重置
else:
if random.random() < p:
line.append(next_city)#添加进路径
dis_matrix.loc[:,next_city] = math.pow(10,10)#更新距离矩阵
now_city = next_city#更新当前城市
i += 1
j = 0#重置
else:
#不接受当前城市作为下一个城市
dis_matrix.loc[now_city,next_city] = math.pow(10,10)#更新距离矩阵
return line
#画路径图
def draw_path(line,CityCoordinates):
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
#SA参数
Tend = 0.1
T = 100
beta = 0.98
#p = 1/(1+math.exp(-0.03*T)) #S型曲线
best_value = math.pow(10,10)#较大的初始值,存储最优解
best_line = []#存储最优路径
#随机生成城市数据,城市序号为0,1,2,3...
# CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]
#计算城市间距离
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
#循环
while T >= Tend:
p = 1/(1+math.exp(-0.03*T))#概率
line = greedy(CityCoordinates,dis_matrix,p)#路径
value = calFitness(line,dis_matrix)#路径距离
if value < best_value:#优于最优解
best_value,best_line = value,line#更新最优解
print("当前最优解%.1f" % (best_value))
T *= beta#更新T
#路径顺序
print(best_line)
#画路径图
draw_path(best_line,CityCoordinates)
#show
当前最优解647.2 当前最优解503.2 当前最优解478.4 当前最优解476.5 当前最优解457.9 [10, 7, 1, 19, 15, 16, 6, 2, 18, 9, 13, 14, 3, 0, 11, 12, 17, 4, 8, 5]
# -*- coding: utf-8 -*-
"""
蚁群算法求解TSP问题
随机在(0,101)二维平面生成20个点
距离最小化
"""
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 添加这条可以让图形显示中文
#计算路径距离,即评价函数
def calFitness(line,dis_matrix):
dis_sum = 0
dis = 0
for i in range(len(line)-1):
dis = dis_matrix.loc[line[i],line[i+1]]#计算距离
dis_sum = dis_sum+dis
dis = dis_matrix.loc[line[-1],line[0]]
dis_sum = dis_sum+dis
return round(dis_sum,1)
def intialize(CityCoordinates,antNum):
"""
初始化,为蚂蚁分配初始城市
输入:CityCoordinates-城市坐标;antNum-蚂蚁数量
输出:cityList-蚂蚁初始城市列表,记录蚂蚁初始城市;cityTabu-蚂蚁城市禁忌列表,记录蚂蚁未经过城市
"""
cityList,cityTabu = [None]*antNum,[None]*antNum#初始化
for i in range(len(cityList)):
city = random.randint(0, len(CityCoordinates)-1)#初始城市,默认城市序号为0开始计算
cityList[i] = [city]
cityTabu[i] = list(range(len(CityCoordinates)))
cityTabu[i].remove(city)
return cityList,cityTabu
def select(antCityList,antCityTabu,trans_p):
'''
轮盘赌选择,根据出发城市选出途径所有城市
输入:trans_p-概率矩阵;antCityTabu-城市禁忌表,即未经过城市;
输出:完整城市路径-antCityList;
'''
while len(antCityTabu) > 0:
if len(antCityTabu) == 1:
nextCity = antCityTabu[0]
else:
fitness = []
for i in antCityTabu:
fitness.append(trans_p.loc[antCityList[-1],i])#取出antCityTabu对应的城市转移概率
sumFitness = sum(fitness)
randNum = random.uniform(0, sumFitness)
accumulator = 0.0
for i, ele in enumerate(fitness):
accumulator += ele
if accumulator >= randNum:
nextCity = antCityTabu[i]
break
antCityList.append(nextCity)
antCityTabu.remove(nextCity)
return antCityList
def calTrans_p(pheromone,alpha,beta,dis_matrix,Q):
'''
根据信息素计算转移概率
输入:pheromone-当前信息素;alpha-信息素重要程度因子;beta-启发函数重要程度因子;dis_matrix-城市间距离矩阵;Q-信息素常量;
输出:当前信息素+增量-transProb
'''
transProb = Q/dis_matrix # 初始化transProb存储转移概率,同时计算增量
for i in range(len(transProb)):
for j in range(len(transProb)):
transProb.iloc[i,j] = pow(pheromone.iloc[i,j], alpha) * pow(transProb.iloc[i,j], beta)
return transProb
def updatePheromone(pheromone,fit,antCity,rho,Q):
'''
更新信息素,蚁周算法
输入:pheromone-当前信息素;fit-路径长度;antCity-路径;rho-信息素挥发因子;Q-信息素常量
输出:更新后信息素-pheromone
'''
for i in range(len(antCity)-1):
pheromone.iloc[antCity[i],antCity[i+1]] += Q/fit
pheromone.iloc[antCity[-1],antCity[0]] += Q/fit
return pheromone
#画路径图
def draw_path(line,CityCoordinates):
x,y= [],[]
for i in line:
Coordinate = CityCoordinates[i]
x.append(Coordinate[0])
y.append(Coordinate[1])
x.append(x[0])
y.append(y[0])
plt.plot(x, y,'-', color='#4169E1', alpha=0.8, linewidth=0.8)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == '__main__':
#参数
CityNum = 20#城市数量
MinCoordinate = 0#二维坐标最小值
MaxCoordinate = 101#二维坐标最大值
iterMax = 100#迭代次数
iterI = 1#当前迭代次数
#ACO参数
antNum = 50#蚂蚁数量
alpha = 2#信息素重要程度因子
beta = 1#启发函数重要程度因子
rho = 0.2#信息素挥发因子
Q = 100.0#常数
best_fit = math.pow(10,10)#较大的初始值,存储最优解
best_line = []#存储最优路径
#随机生成城市数据,城市序号为0,1,2,3...
# CityCoordinates = [(random.randint(MinCoordinate,MaxCoordinate),random.randint(MinCoordinate,MaxCoordinate)) for i in range(CityNum)]
CityCoordinates = [(88, 16),(42, 76),(5, 76),(69, 13),(73, 56),(100, 100),(22, 92),(48, 74),(73, 46),(39, 1),(51, 75),(92, 2),(101, 44),(55, 26),(71, 27),(42, 81),(51, 91),(89, 54),(33, 18),(40, 78)]
#计算城市间距离,生成矩阵
dis_matrix = pd.DataFrame(data=None,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))
for i in range(len(CityCoordinates)):
xi,yi = CityCoordinates[i][0],CityCoordinates[i][1]
for j in range(len(CityCoordinates)):
xj,yj = CityCoordinates[j][0],CityCoordinates[j][1]
if (xi==xj) & (yi==yj):
dis_matrix.iloc[i,j] = round(math.pow(10,10))
else:
dis_matrix.iloc[i,j] = round(math.sqrt((xi-xj)**2+(yi-yj)**2),2)
pheromone = pd.DataFrame(data=Q,columns=range(len(CityCoordinates)),index=range(len(CityCoordinates)))#初始化信息素,所有路径都为Q
trans_p = calTrans_p(pheromone,alpha,beta,dis_matrix,Q)#计算初始转移概率
while iterI <= iterMax:
'''
每一代更新一次环境因素导致的信息素减少,每一代中的每一个蚂蚁完成路径后,都进行信息素增量更新(采用蚁周模型)和转移概率更新;
每一代开始都先初始化蚂蚁出发城市;
'''
antCityList,antCityTabu = intialize(CityCoordinates,antNum)#初始化城市
fitList = [None]*antNum#适应值列表
for i in range(antNum):#根据转移概率选择后续途径城市,并计算适应值
antCityList[i] = select(antCityList[i],antCityTabu[i],trans_p)
fitList[i] = calFitness(antCityList[i],dis_matrix)#适应度,即路径长度
pheromone = updatePheromone(pheromone,fitList[i],antCityList[i],rho,Q)#更新当前蚂蚁信息素增量
trans_p = calTrans_p(pheromone,alpha,beta,dis_matrix,Q)
if best_fit >= min(fitList):
best_fit = min(fitList)
best_line = antCityList[fitList.index(min(fitList))]
#print(iterI,best_fit)#打印当前代数和最佳适应度值
iterI += 1#迭代计数加一
pheromone = pheromone*(1-rho)#信息素挥发更新
print(best_line)#路径顺序
print(best_fit)
draw_path(best_line,CityCoordinates)#画路径图
#show
[8, 4, 17, 12, 5, 16, 10, 7, 1, 19, 15, 6, 2, 18, 9, 13, 3, 0, 11, 14]